-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[lldb] Fix the "RegisterValue::SetValueFromData" method for 128-bit integer registers #163646
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[lldb] Fix the "RegisterValue::SetValueFromData" method for 128-bit integer registers #163646
Conversation
Fix the "RegisterValue::SetValueFromData" so that it works also for 128-bit registers that contain integers.
@llvm/pr-subscribers-lldb Author: Matej Košík (sedymrak) ChangesFix the "RegisterValue::SetValueFromData" so that it works also for 128-bit registers that contain integers. Without this change, the The original version displays the content of the 128-bit registers so that its lower and upper 64-bit halves are swapped. Full diff: https://github.com/llvm/llvm-project/pull/163646.diff 1 Files Affected:
diff --git a/lldb/source/Utility/RegisterValue.cpp b/lldb/source/Utility/RegisterValue.cpp
index 0e99451c3b700..12c349a143c0f 100644
--- a/lldb/source/Utility/RegisterValue.cpp
+++ b/lldb/source/Utility/RegisterValue.cpp
@@ -199,7 +199,7 @@ Status RegisterValue::SetValueFromData(const RegisterInfo ®_info,
else if (reg_info.byte_size <= 16) {
uint64_t data1 = src.GetU64(&src_offset);
uint64_t data2 = src.GetU64(&src_offset);
- if (src.GetByteOrder() == eByteOrderBig) {
+ if (src.GetByteOrder() == eByteOrderLittle) {
int128.x[0] = data1;
int128.x[1] = data2;
} else {
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understood this, the code is trying to make the order inside the APInt always:
least significant 64-bit element, most significant 64-bit element
Because internally APInt expects this no matter the platform endian? Haven't verified that but it's implied.
The first element you'd get from a big endian extractor is actually the most significant, so the two elements need to be reversed.
Which was being done but the wrong way around. Little endian is fine, big endian needs to be swapped.
How did you hit this? I thought I could reach it by running an expression on AArch64 that used a v
register, but because I need to use float or double to do that, it's always marked as a float type and takes that path.
The fix seems correct but I'd like to be able to test this. Though it will likely only get run with little endian, it'd be something.
Might be able to make something synthetic via the SBAPI.
Steps to reproduce the problem: (1) Create a program that writes a 128-bit number to a 128-bit registers
(2) Compile this program with LLVM compiler:
(3) Modify LLDB so that when it will be reading value from the
(4) Observe what happens how LLDB will print the content of this register after it was initialized with 128-bit value.
You can see that the upper and lower 64-bit wide halves are swapped. |
Thanks for the reproducer. Please include it in the PR description as well, as it may be the closest thing we get to a test case. I'm still not clear how you found this, but if the answer is:
Then the conclusion is the same. Hard to test this with an upstream target. We have faked targets in testing before, so I think we could fake an AArch64 where V registers were not vectors, as this type is set in the XML sent from the debug server. Then again, I found that there's no public API for this call. Running an expression on a fake target like that could work but it'd be a lot of mock stuff to implement (for a start, we'd need to pretend it can JIT code). We have some tests that put a simulated debug sever in front of a real one, but that's too much effort for this fix. Let me think about it for a bit. If I don't come up with anything then I'll approve this, as it does look correct to me. |
I am not sure if I understand correctly what you meant I should do.
The problem floated to the surface when we adapted LLDB for debugging programs written in a custom programming language that supports non-standard integer sizes for registers as well as variables that, in this case, are treated as registers.
I am not aware of any platform where this bug could be directly reproduced. I am not sure how much it would help, but I plan (tomorrow) to look at related unit-tests. I need to know:
At worst I will learn why it cannot be done...
+1 |
Yes, thanks.
I doubt this ever had coverage because no target ever tried this. Those unit tests look promising though, if we can set the type of the register value. |
My idea with the fake target is going to be way too much work, the unittests is a better idea. I got this to fail:
You can use that with some cleanup if you can confirm that your change fixes it. May need repeating for little and big endian extractors, though that may also swap the order within the uint64s so watch out for that. |
I came to the same conclusion a little later than you.
nicely failed on the I will think about it and push something today. |
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good just one refactoring suggestion.
I like the design of having one target value and changing the inputs. I've tried to do it the other way around in the past and it always seemed harder to comprehend.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
I can merge it for you if needed, let me know.
That would be great. If you can, please do that. |
Before I can merge this, please update your GitHub email settings - https://llvm.org/docs/DeveloperPolicy.html#email-addresses (your email does show up in |
No problem. |
Fix the
RegisterValue::SetValueFromData
method so that it works also for 128-bit registers that contain integers.Without this change, the
RegisterValue::SetValueFromData
method does not work correctlyfor 128-bit registers that contain (signed or unsigned) integers.
Steps to reproduce the problem:
(1)
Create a program that writes a 128-bit number to a 128-bit registers
xmm0
. E.g.:(2)
Compile this program with LLVM compiler:
(3)
Modify LLDB so that when it will be reading value from the
xmm0
register, instead of assuming that it is vector register, it will treat it as if it contain an integer. This can be achieved e.g. this way:(4)
Rebuild the LLDB.
(5)
Observe what happens how LLDB will print the content of this register after it was initialized with 128-bit value.
You can see that the upper and lower 64-bit wide halves are swapped.